package bean;

import collection.UtilCollection;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import utils.UtilClassType;

import java.lang.reflect.Field;
import java.rmi.UnexpectedException;
import java.util.*;



public class UtilBean {
	private static Logger logger=LoggerFactory.getLogger(UtilBean.class);
	
	
	
	
	//定义简单类名数组：
		//简单类包括:原始类、包装类、String，类名为小写，且为simpleName
		public static List<String> SIMPLE_CLASSES_List=Arrays.asList("boolean","byte","char","short",
			"int","long","float","double","String","Boolean",
			"Byte","Char","Short",
			"Int","Long","Float","Double","Integer");
		

		
		/*//复制2个bean之间的简单属性
		public static void CopySimpleProperties(Object src,Object desc){
		}*/
		public static <T> T copyPropertiesByFieldNames(T source,T target,Collection<String> includFiedlNameCollection){
			if(source==null){
				return null;
			}
			if(target==null){
				throw new RuntimeException("target domain is null");
			}
			List<String> allFieldNameList=UtilBeanInfo.getFiledNameList(source.getClass());
			logger.info(allFieldNameList+"");
			allFieldNameList.removeAll(includFiedlNameCollection);
			logger.info(allFieldNameList+"");
			String[] ignoreProperties= UtilCollection.collection2Array(String.class, allFieldNameList);
			BeanUtils.copyProperties(source, target, ignoreProperties);
			return target;
		}
		
		public static <T> T copyPropertiesByFieldNames(T source,T target,String... includFiedlNames){
			if(includFiedlNames==null){
				return target;
			}
			List<String> list=Arrays.asList(includFiedlNames);
			copyPropertiesByFieldNames(source,target,list);
			return target;
		}
		
	    


	/**
	 * 为对象 中 相应 属性 设置为null,其中 在对象属性中的 ：T;T[];Collection<T>都可关联进行处理.
	 * @param clazz 预处理 类型 T
	 * @param fieldNameSet 设置为Null的属性名称
	 * @return 处理后的对象
	 * @throws IllegalArgumentException
	 * @throws IllegalAccessException
	 * @throws InstantiationException 
	 */
	public static <T> T setObjectFieldNull(Class<T> clazz,T t,Set<String> fieldNameSet) throws IllegalArgumentException, IllegalAccessException, InstantiationException{
		if(t==null){
			return null;
		}
		if(fieldNameSet==null || fieldNameSet.size()==0){
			return t;
		}
		Field[] fields=t.getClass().getDeclaredFields();
		for(Field field:fields){
			field.setAccessible(true);
			String fieldName=field.getName();
			Object fieldValue=field.get(t);
			Class fieldClass=field.getType();
			
			//如果 fieldValue为空 或者 fieldNameSet包含 fieldName，设置为空后，遍历下一属性
			if(fieldValue==null) continue;
			if(fieldNameSet.contains(fieldName)){
				field.set(t, null);
				continue;
			}
			
			//fieldValue为以下3种情况需要递归:1.T[] ; 2,Collection<T>   3.T
			//1.
			if(fieldClass.isArray()){
				Object[] objects=(Object[]) fieldValue;
//				logger.debug(field.getName() + " = " +fieldValue);
				for(Object object:objects){
					if(object.getClass()==clazz){
						setObjectFieldNull(clazz,(T)object,fieldNameSet);
					}else{
						break;
					}
				}
			} 
			//2.
			if(fieldValue instanceof Collection){
				//logger.debug(field.getName() + " = " +fieldValue);
				for(Object object:(Collection)fieldValue){
					if(object.getClass()==clazz){
						setObjectFieldNull(clazz,(T)object,fieldNameSet);
					}else {
						break;
					}
					
				}
			}
			//3.
			if(fieldClass==clazz){
				logger.debug(field.getName() + " = " +fieldValue);
				setObjectFieldNull(clazz,(T)fieldValue,fieldNameSet);
			}
		}
		return t;
	}
	
	/**
	 * 为对象 中  在排除列表为的 属性 设置为null,其中 在对象属性中的 ：T;T[];Collection<T>都可关联进行处理.
	 * @param clazz 预处理 类型 T
	 * @param t  预处理的对象，可以为 对象 T、数组 T[] 或集合 Collection<T>
	 * @param fieldNameKeepSet 保留原属性的名称
	 * @return 处理后的对象
	 * @throws IllegalArgumentException
	 * @throws IllegalAccessException
	 * @throws InstantiationException 
	 */
	public static <T> T setObjectFieldNullExcept(Class<T> clazz,T t,Set<String> fieldNameKeepSet) 
			throws IllegalArgumentException, IllegalAccessException, InstantiationException{
		if(t==null){
			return null;
		}
		if(fieldNameKeepSet==null || fieldNameKeepSet.size()==0){
			return null;
		}
		Set<String> fieldNameSet=new HashSet<>();
		Field[] fields=t.getClass().getDeclaredFields();
		for(Field field:fields){
			fieldNameSet.add(field.getName());
		}
		fieldNameSet.removeAll(fieldNameKeepSet);
		return setObjectFieldNull(clazz,t,fieldNameSet);
	}
	
	//重载 setObjectFieldNull
	public static <T> T setObjectFieldNull(Class<T> clazz,T t,String... fieldNames) throws IllegalArgumentException, IllegalAccessException, InstantiationException{
		Set<String> fieldNameSet=new HashSet<>();
		if(fieldNames!=null){
			for(String fieldName:fieldNames ){
				fieldNameSet.add(fieldName);
			}
		}
		return setObjectFieldNull(clazz, t, fieldNameSet);
	}
	
	
	//重载 setObjectFieldNullExcept
	public static <T> T setObjectFieldNullExcept(Class<T> clazz,T t,String... fieldNames) 
			throws IllegalArgumentException, IllegalAccessException, InstantiationException{
		Set<String> fieldNameSet=new HashSet<>();
		if(fieldNames!=null){
			for(String fieldName:fieldNames ){
				fieldNameSet.add(fieldName);
			}
		}
		return setObjectFieldNullExcept(clazz, t, fieldNameSet);
	}

	public static <T> List<T> setObjectFieldNullExcept(
			Class<T> clazz, List<T> list, String[] fieldArray) throws IllegalArgumentException, IllegalAccessException, InstantiationException {
		// TODO Auto-generated method stub
		if(list==null ){
			return null;
		}else{
			for(T t:list){
				setObjectFieldNullExcept(clazz,t,fieldArray);
			}
			return list;
		}
	}
	
	
	    /**
	     * @throws InstantiationException 
	     * @throws SecurityException 
	     * @throws NoSuchFieldException 
	    * @Title: cycleCopyWithProperties
	    * @Description: 根据属性列表复制bean,domain 中的第一层T,T[],List<T>,Set<T> 也进行根据设置属性进行循环复制.
	    * @param @param clazz
	    * @param @param t
	    * @param @param propertySet
	    * @param @return
	    * @param @throws IllegalArgumentException
	    * @param @throws IllegalAccessException    
	    * @return T    
	    * @throws
	    */
	public static <T> T  cycleCopyIncludeProperties(Class<T> clazz,T t,Set<String> propertySet) throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException, InstantiationException{
		if(t==null){
			return null;
		}
		if(propertySet==null || propertySet.size()==0){
			return t;
		}
		
		Set<String> fieldSet=new HashSet<>();
		T copyBean=clazz.newInstance();
		
		
		Field[] fields=t.getClass().getDeclaredFields();
		Field[] copyFields=copyBean.getClass().getDeclaredFields();
		
		for(Field field:fields){
			fieldSet.add(field.getName());
		}
		
		if(!fieldSet.containsAll(propertySet)){
			throw new RuntimeException("输入属性参数错误");
		}
		
		for(String propertyName:propertySet){
			Field field=t.getClass().getDeclaredField(propertyName);
			field.setAccessible(true);
			String fieldName=field.getName();
			Object fieldValue=field.get(t);
			Class fieldClass=field.getType();
			Field copyField=copyBean.getClass().getDeclaredField(fieldName);
			copyField.setAccessible(true);
			Object copyValue=copyField.get(copyBean);
			copyField.setAccessible(true);
		//	System.out.println("*****************");
		//	logger.info(copyBean.toString());
		//	logger.info(fieldName);
		
			//如果 fieldValue为空 ，设置为空后，遍历下一属性
			if(fieldValue==null) {
				field.set(copyBean,null);
				continue;
			}
			
			//4 种属性 特殊对待  T ,T[] List<T>;Set<T>
			//其余直接使用beanutil复制属性
			
			//1. 如果为 T 类型 ，递归copy
			if(fieldClass==clazz){
				T copy=cycleCopyIncludeProperties(clazz, t, propertySet);
				field.set(copyBean, copy);
				continue;
			}
			
			//2. 如果 T[],递归copy
			if(fieldClass.isArray()){
				Object[] objects=(Object[]) fieldValue;
				logger.debug(field.getName() + " = " +fieldValue);
				if(objects.length>0){
					if(objects[0].getClass()==clazz){
						Object[] copyArray=new Object[objects.length];
						for(int i=0;i<objects.length;i++){
								T copy=cycleCopyIncludeProperties(clazz,(T)objects[i],propertySet);
								copyArray[i]=copy;
						}
						field.set(copyBean, (Object)copyArray);
						continue;
					}
				}
			} 
			//3.List<T>, 递归copy
			if(fieldValue instanceof List){
			//	logger.debug(field.getName() + " = " +fieldValue);
				List<T> copyList=new ArrayList<>();
				for(Object object:(List)fieldValue){
					if(object.getClass()==clazz){
						T copy=cycleCopyIncludeProperties(clazz,(T)object,propertySet);
						copyList.add(copy);
					}
				}
				field.set(copyBean, copyList);
				continue;
			}
			
			//4.Set<T>, 递归copy
			if(fieldValue instanceof Set){
				//logger.debug(field.getName() + " = " +fieldValue);
				Set<T> copySet=new HashSet<>();
				for(Object object:(Set)fieldValue){
					if(object.getClass()==clazz){
						T copy=cycleCopyIncludeProperties(clazz,(T)object,propertySet);
						copySet.add(copy);
					}
				}
				field.set(copyBean, copySet);
				continue;
			}
			if(UtilClassType.isSimpleType(fieldClass)){
				field.set(copyBean, fieldValue);
		//		logger.info(fieldValue.toString());
			}else{
				copyValue=fieldClass.newInstance();
				BeanUtils.copyProperties(fieldValue, copyValue);
				field.set(copyBean, copyValue);
				logger.info(copyValue.toString());
			}
		}
		return copyBean;
	}
	

	
	    /**
	     * @throws UnexpectedException 
	     * @throws InstantiationException 
	     * @throws SecurityException 
	     * @throws NoSuchFieldException 
	     * @throws IllegalAccessException 
	     * @throws IllegalArgumentException 
	    * @Title: cycleCopyWithProperties
	    * @Description: 重载方法：根据属性列表复制bean,domain 中的第一层T,T[],List<T>,Set<T> 也进行根据设置属性进行循环复制.
	    * @param @param clazz
	    * @param @param t
	    * @param @param propertiest
	    * @param @return    
	    * @return T    
	    * @throws
	    */
	public static <T> T  cycleCopyIncludeProperties(Class<T> clazz,T t,String... properties) throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException, InstantiationException, UnexpectedException{
			if(properties==null || properties.length==0){
				throw new UnexpectedException("过滤属性参数:properties 错误");
			}
			Set<String> propertySet=new HashSet<>();
			for(String property:properties){
				propertySet.add(property);
			}
			return cycleCopyIncludeProperties(clazz, t, propertySet);
	}
	
	
	    /**
	    * @Title: cycleCopyExcludeProperties
	    * @Description: 根据排除属性列表复制bean,domain 中的第一层T,T[],List<T>,Set<T> 也进行根据设置属性进行循环复制.
	    * @param @param clazz
	    * @param @param t
	    * @param @param excludePropertySet
	    * @param @return
	    * @param @throws IllegalArgumentException
	    * @param @throws IllegalAccessException
	    * @param @throws NoSuchFieldException
	    * @param @throws SecurityException
	    * @param @throws InstantiationException    
	    * @return T    
	    * @throws
	    */
	public static <T> T  cycleCopyExcludeProperties(Class<T> clazz,T t,Set<String> excludePropertySet) throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException, InstantiationException{
		Field[] fields=clazz.getDeclaredFields();
		Set<String> propertySet=new HashSet<>();
		for(Field f:fields){
			propertySet.add(f.getName());
		}
		propertySet.removeAll(excludePropertySet);
		return cycleCopyIncludeProperties(clazz,t,propertySet);
	}
	
	 /**
	 * @throws UnexpectedException 
	    * @Title: cycleCopyExcludeProperties
	    * @Description: 重载方法：根据排除属性列表复制bean,domain 中的第一层T,T[],List<T>,Set<T> 也进行根据设置属性进行循环复制.
	    * @param @param clazz
	    * @param @param t
	    * @param @param excludePropertySet
	    * @param @return
	    * @param @throws IllegalArgumentException
	    * @param @throws IllegalAccessException
	    * @param @throws NoSuchFieldException
	    * @param @throws SecurityException
	    * @param @throws InstantiationException    
	    * @return T    
	    * @throws
	    */
	public static <T> T  cycleCopyExcludeProperties(Class<T> clazz,T t,String... excludeProperties) throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException, InstantiationException, UnexpectedException{
		if(excludeProperties==null || excludeProperties.length==0){
			throw new UnexpectedException("过滤属性参数:properties 错误");
		}
		Set<String> excludePropertySet=new HashSet<>();
		for(String property:excludeProperties){
			excludePropertySet.add(property);
		}
		return cycleCopyIncludeProperties(clazz,t,excludePropertySet);
	}
	
	
	    /**
	    * @Title: getCopyInludeProperties
	    * @Description: 获得T 的复制bean,仅包括需要的属性，底层使用spring的BeanUtil.copyProperties
	    * @param @param clazz
	    * @param @param t
	    * @param @param includePropertiesSet 需要复制的属性
	    * @param @return
	    * @param @throws InstantiationException
	    * @param @throws IllegalAccessException    
	    * @return T    
	    * @throws
	    */
	public static  <T> T getCopyInludeProperties(Class<T> clazz,T t,Set<String> includePropertiesSet) throws InstantiationException, IllegalAccessException{
		T copyBean=clazz.newInstance();
		if(UtilCollection.isNullOrEmpty(includePropertiesSet)){
			BeanUtils.copyProperties(t, copyBean);
			return copyBean;
		}
		
		Field[]	 fields=clazz.getDeclaredFields();
		Set<String> fieldSet=new HashSet<>();
		for(Field field:fields){
			fieldSet.add(field.getName());
		}
		fieldSet.removeAll(includePropertiesSet);

		String[] ignoreProperties=UtilCollection.collection2Array(String.class, fieldSet);
		
		BeanUtils.copyProperties(t, copyBean, ignoreProperties);
		return copyBean;
	}
	
	public static  <T> T getCopyInludeProperties(Class<T> clazz,T t,String... includeProperties) throws InstantiationException, IllegalAccessException{
		Set<String> propertiesSet=new HashSet<String>();
		if(includeProperties==null || includeProperties.length==0){
			
			return getCopyInludeProperties(clazz,t,propertiesSet);
		}
		for(String property:includeProperties){
			propertiesSet.add(property);
		}
		return getCopyInludeProperties(clazz, t, propertiesSet);
	}
	
	public static  <T> List<T> getCopyInludeProperties(Class<T> clazz,List<T> sourceList,Set<String> includePropertiesSet) throws InstantiationException, IllegalAccessException{
		if(sourceList==null){
			return null;
		}
		List<T>	copyList=new ArrayList<>();
		for(T t:sourceList){
			T copy=getCopyInludeProperties(clazz,t,includePropertiesSet);
			copyList.add(copy);
		}
		return copyList;
	}
		
	public static  <T> List<T> getCopyInludeProperties(Class<T> clazz,List<T> sourceList,String... includeProperties) throws InstantiationException, IllegalAccessException{
		if(sourceList==null){
			return null;
		}
		logger.info(sourceList.size()+"");
		List<T>	copyList=new ArrayList<>();
		for(T t:sourceList){
			T copy=getCopyInludeProperties(clazz,t,includeProperties);
			copyList.add(copy);
		}
		return copyList;
	}
	
	public static <T> Set<T> getCopyInludeProperties(Class<T> clazz,Set<T> sourceSet,Set<String> includePropertiesSet) throws InstantiationException, IllegalAccessException{
		if(sourceSet==null){
			return null;
		}
		Set<T>	copySet=new HashSet<>();
		for(T t:sourceSet){
			T copy=getCopyInludeProperties(clazz,t,includePropertiesSet);
			copySet.add(copy);
		}
		return copySet;
	}
		
	public static <T> Set<T> getCopyInludeProperties(Class<T> clazz,Set<T> sourceSet,String... includeProperties) throws InstantiationException, IllegalAccessException{
		if(sourceSet==null){
			return null;
		}
		Set<T>	copySet=new HashSet<>();
		for(T t:sourceSet){
			T copy=getCopyInludeProperties(clazz,t,includeProperties);
			copySet.add(copy);
		}
		return copySet;
	}
	

    
    /**
     * 获取对象属性名 所组成的 数组
     * */
    public static String[] getFiledName(Object o){
    	Field[] fields=o.getClass().getDeclaredFields();
       	String[] fieldNames=new String[fields.length];
    	for(int i=0;i<fields.length;i++){
    		System.out.println(fields[i].getType());
    		fieldNames[i]=fields[i].getName();
    	}
    	return fieldNames;
    }
    

}
		
